import React, { PureComponent } from 'react';
import WPT from 'wpt';

const fillZero = (v, len = 2) => {
    return `${'0'.repeat(Math.max(0, len - `${v}`.length))}${v}`;
}

const defaultReduce = [60, 60, 24, 30, 12, 1];

export function formatTime(CountdownTime, fmt = 'YYYY-MM-DD hh:mm:ss', reduce = defaultReduce) {
    // 只有s的话 则只显示秒倒计时
    if (fmt.includes('s')
        && !fmt.includes('m')
        && !fmt.includes('h')
        && !fmt.includes('Y')
        && !fmt.includes('M')
        && !fmt.includes('D')
    ) {
        return fmt.replace(/s{1,}/g, Math.floor(CountdownTime));
    }
    const [s, m, h, d, M, y] = reduce.map(PER => {
        const result = CountdownTime % PER;
        // 得到更高位的值
        CountdownTime = Math.floor(CountdownTime / PER);
        return Math.floor(result);
    });

    const H = d * 24 + h; // 总小时数

    const INFO = {
        y,
        Y: y,
        M,
        d,
        D: d,
        h,
        m,
        s,
        H,
    };
    // 替换数据
    return fmt.replace(/(y|Y){1,}|M{1,}|(d|D){1,}|H{1,}|h{1,}|m{1,}|s{1,}/g, str => fillZero(INFO[str[0]], str.length).slice(-str.length)
    );
}

// 毫秒级倒计时
export class Msec extends PureComponent {
    static defaultProps = {
        nowTime: 0,
        endTime: 0,
        onChange: () => {}, // 时间发生变化
        onEnd: () => {}, // 倒计时结束
        isShowHour: true, // 如果小时不为0，不显示毫秒
    };

    state = {
        nowTime: this.props.nowTime,
        leftTime: 0,
        baseTime: Date.now() / 1000, // 时间差
    };

    componentDidMount() {
        this.autoRun();
    }

    componentWillUnmount() {
        this.clearInterval();
    }

    clearInterval = () => {
        WPT.Interval.clear(this.intervalKey);
        window.clearInterval(this.msecInterval);
    };

    intervalKey = WPT.Util.uuid();

    autoRun = () => {
        this.clearInterval();
        const { len } = this.props
        WPT.Interval.append(this.intervalKey, () => {
            const { endTime } = this.props;
            const { nowTime } = this.state;
            const leftTime = Math.floor(Date.now() / 1000) - this.state.baseTime; // 已经过去的时间

            this.props.onChange(nowTime + leftTime); // 时间发生变化
            if (leftTime > endTime - nowTime) {
                this.clearInterval();
                // 毫秒停止在00
                if (this.$msec) {
                    this.$msec.innerHTML = fillZero(0);
                }
                this.props.onEnd(); // 倒计时结束
                return;
            }

            this.setState({
                leftTime,
            });
            this.rendermsec(len);
        });
        this.rendermsec(len);
    };

    msecInterval = null;

    // 渲染毫秒
    rendermsec(len = 2) {
        window.clearInterval(this.msecInterval);
        let msec = this.props.msecFrom || 99;
        let interval = 1000 / (msec + 1)
        // 第一次渲染
        if (this.$msec) {
            this.$msec.innerHTML = fillZero(msec, len);
        }
        this.msecInterval = this.$msec
        
            && setInterval(() => {
                msec -= 1;
                if (msec < 0) {
                    msec = this.props.msecFrom || 99;
                }
                if (this.$msec) {
                    this.$msec.innerHTML = fillZero(msec, len);
                }
            }, interval);
    }

    render() {
        const {
            className = '', style = {}, isShowHour, render
        } = this.props;
        const cutDwonTime = this.props.endTime - this.state.nowTime - this.state.leftTime; // 剩余多少秒

        if (cutDwonTime < 0) {
            return null;
        }

        if (render) {
            return render({
                cutDwonTime,
                formatTime,
                mescRef: d => {
                    this.$msec = d;
                },
            });
        }

        const hour = cutDwonTime > 60 * 60; // 剩余小时大于0
        const format = isShowHour && hour ? 'hh:mm:ss' : 'mm:ss';
        const html = formatTime(cutDwonTime, format).replace(/\d+/g, $0 => `<span class="time">${$0}</span>`);

        return (
            <div className={`${className} msectime`} style={style}>
                <span dangerouslySetInnerHTML={{ __html: html }} />
                {(!isShowHour || !hour) && (
                    <span>
                        :
                        <span
                            className="time"
                            ref={d => {
                                this.$msec = d;
                            }}
                        />
                    </span>
                )}
            </div>
        );
    }
}

// 秒级倒计时
export default class extends PureComponent {
    static defaultProps = {
        nowTime: 0,
        endTime: 0,
        format: '距离结束还剩 hh 时 mm 分 ss 秒', // 时间格式
        reduce: defaultReduce,
        alwaysShow: false, // 是否始终显示，倒计时为0依旧显示
        onChange: () => {},
        onEnd: () => {},
    };

    state = {
        nowTime: this.props.nowTime,
        leftTime: 0,
        baseTime: Date.now() / 1000, // 时间差
    };

    componentDidMount() {
        this.autoRun();
    }

    componentWillUnmount() {
        this.clearInterval();
    }

    clearInterval = () => {
        WPT.Interval.clear(this.intervalKey);
    };

    intervalKey = WPT.Util.uuid();

    autoRun = () => {
        this.clearInterval();
        WPT.Interval.append(this.intervalKey, () => {
            const { endTime } = this.props;
            const { nowTime } = this.state;
            const leftTime = Math.floor(Date.now() / 1000) - this.state.baseTime; // 已经过去的时间

            this.props.onChange(nowTime + leftTime); // 时间发生变化
            if (leftTime > endTime - nowTime) {
                this.clearInterval();
                this.props.onEnd(); // 倒计时结束
                return;
            }
            this.setState({
                leftTime,
            });
        });
    };

    render() {
        const { className = '', style = {}, alwaysShow } = this.props;
        let cutDwonTime = this.props.endTime - this.state.nowTime - this.state.leftTime; // 剩余多少

        if (cutDwonTime < 0) {
            cutDwonTime = 0;
            
            if (!alwaysShow) {
                return null;
            }
        }

        if (this.props.render) {
            return this.props.render(cutDwonTime);
        }

        const html = formatTime(cutDwonTime, this.props.format, this.props.reduce).replace(
            /\d+/g,
            $0 => `<span class="time" style="display: inline-flex; align-items: center;">${$0
                .split('')
                .map(i => `<span>${i}</span>`)
                .join('')}</span>`
        );

        return <div dangerouslySetInnerHTML={{ __html: html }} className={className} style={style} />;
    }
}
